package multithreading;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 实现线程有三种方式
 *      1. 编写一个类，直接继承java.lang.Thread，重写run方法，调用线程对象的start()方法启动线程，但无法获取线程返回值
 *      2. 编写一个类，实现java.lang.Runnable接口，实现run方法，调用线程对象的start()方法启动线程，但无法获取线程返回值
 *              实现Runnable接口比较常用，因为一个类实现了接口，它还可以去继承其它的类，更灵活
 *      3. 实现Callable接口（JDK8新特性），可以获取线程返回值
 *              缺点：效率比较低，在获取某个线程执行结果的时候，当前线程受阻塞
 *
 * thread.run()     run()不会启动线程，只是普通的调用方法而已。不会分配新的分支栈
 * thread.start()   启动一个分支线程，在JVM中开辟一个新的栈空间，这段代码任务完成之后，瞬间就结束了
 *                  这段代码的任务只是为了开启一个新的栈空间，只要新的栈空间开出来，start()方法就结束了。线程就启动成功了。
 *                  启动成功的线程会自动调用run方法，并且run方法在分支栈的栈底部（压栈）。
 *                  run方法在分支栈的栈底部，main方法在主栈的栈底部。run和main是平级的
 *
 * Thead类
 * 构造方法
 * Thread()
 * Thread(String name)          参数name表示线程名
 * Thread(Runnable target)
 * Thread(Runnable target, String name)
 *
 * static Thread currentThread()    获取当前线程对象
 * static void yield()              使当前线程主动放弃cpu时间片
 *          Thread.yield();
 *
 * String getName()                 获取线程对象名字
 * void setName(String name)        修改线程对象名字
 *
 * static void sleep(long millis)   让当前线程休眠millis毫秒
 * void interrupt()                 终止线程的睡眠，即线程中断sleep()方法的设置
 * public boolean isInterrupted()   判断线程是否被中断
 * public boolean isAlive()         判断线程是否还活着
 * public boolean isDaemon()        判断线程是否为守护线程
 *
 * public void run()        线程任务方法，需要重写该方法
 * public void start()      线程启动方法
 *
 * 注意：run()方法只能try…catch…不能throws
 *      因为run()方法在父类中没有抛出任何异常，子类不能比父类抛出更多的异常
 *
 *
 * 线程调度方法
 * int getPriority()                    获得线程优先级
 * void setPriority(int newPriority)    设置线程优先级
 *              1~10
 *              最低优先级1          Thread.MIN_PRIORITY
 *              默认优先级是5
 *              最高优先级10         Thread.MAX_PRIORITY
 *              并不是所有操作系统都支持10级优先级的划分
 *              java只是给操作系统一个优先级的参考值，线程的优先级最终还是由操作系统决定
 * static void yield()      让位方法，当前线程暂停（阻塞），回到就绪状态，让给其它线程
 *                          不是阻塞方法
 * void join()      将一个线程合并到当前线程中，当前线程受阻塞，直到加入的线程执行结束后才继续当前线程
 * void join(long millis)               同join()，等待该线程终止的时间最长为millis毫秒
 * void join(long millis, int nanos)    同join()，等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒
 *
 * void setDaemon(boolean on)           on为true表示把线程设置为守护线程
 *
 *
 *
 * 定时器
 * Timer类
 * 构造方法：
 *      Timer()                     创建一个定时器
 *      Timer(boolean isDaemon)     isDaemon为true为守护线程定时器
 *      Timer(String name)          创建一个定时器，其线程名字为name
 *      Timer(String name, boolean isDaemon)    结合第2、3个构造方法
 *
 * 实例方法
 * void schedule(TimerTask task, Date firstTime, long period)   安排指定的任务在指定的时间开始进行重复的固定延迟
 *                                  task        定时任务
 *                                  firstTime   第一次执行时间
 *                                  period      每隔period毫秒执行一次
 * void cancel()    终止定时器
 *
 *
 *
 * Object类的wait()、notify()、notifyAll()方法
 *      不是线程对象的方法，是java中任何一个java对象都有的方法，是Object类中自带的，不能通过线程对象调用
 * void wait()          让活动在当前对象的线程无限等待（释放之前占有的锁）
 * void notify()        唤醒在当前对象上等待的线程（只提示唤醒，不会释放锁）
 * void notifyAll()     唤醒在当前对象上等待的全部线程（只提示唤醒，不会释放锁）
 * */
public class ThreadDemo extends Thread {
    public ThreadDemo(String name) {
        super(name);
    }
    public void run() {     // 重写run方法
        Thread cThead = Thread.currentThread();
        String name = cThead.getName();
        System.out.println(name);
        try {
            sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        cThead.setName("修改线程对象名");
        System.out.println(cThead.getName());
        System.out.println("线程优先级：" + cThead.getPriority());
        System.out.println("当前正在执行的线程：" + Thread.currentThread().getName());
//        Thread.yield();
        Thread thread = new Thread(() -> {
            System.out.println("加入的新线程开始执行");
            for (int i = 0; i < 10; i++) {
                System.out.println("当前正在执行的线程：" + Thread.currentThread().getName());
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("新加入的线程执行完毕");
        });
        thread.start();
        try {
            thread.join();  // 需在调用start()方法启动新线程之后调用join()方法才能将新线程加入到当前线程中
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("当前正在执行的线程：" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        ThreadDemo thread = new ThreadDemo("线程对象名");
        thread.start();     // 启动线程

        // 第一步：创建一个“未来任务类”对象，参数非常重要，需要给一个Callable接口实现类对象
        FutureTask task = new FutureTask(new Callable() {
            @Override
            public Object call() throws Exception { // call()方法就相当于run方法
                // 线程执行一个任务，执行之后可能会有一个执行结果
                // 模拟执行
                System.out.println("call method begin");
                Thread.sleep(1000 * 10);
                System.out.println("call method end!");
                int a = 100;
                int b = 200;
                return a + b; //自动装箱(300结果变成Integer)
            }
        });
        Thread thread1 = new Thread(task);
        thread1.start();
        try {
            Object obj = task.get();    // 获取线程的返回值，会阻塞当前线程
            System.out.println("线程执行结果:" + obj);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
